/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2023-2023.
 * Description: support hisi-1380 SoC double cluster booting.
 * Author: wanqian <wanqian10@huawei.com>
 * Create: 2023-09-05
 * Note: this file isn't compiled independently, it is includded
 * in 8250_core.c
 */

#if defined(CONFIG_SERIAL_8250_CONSOLE) && defined(CONFIG_RTOS_HAL_DOUBLE_CLUSTER)
atomic_t printk_enable;
void set_printk_uart(int val)
{
	atomic_set(&printk_enable, val);
}
EXPORT_SYMBOL(set_printk_uart);

int is_printk_uart_enable(void)
{
	return atomic_read(&printk_enable);
}
EXPORT_SYMBOL(is_printk_uart_enable);
#endif

#if defined(CONFIG_RTOS_HAL_UART_SUSPEND) || defined(CONFIG_RTOS_HAL_DOUBLE_CLUSTER) \
       || defined(CONFIG_RTOS_HAL_WORKAROUND_UART_USE_DEFAULT_DIVISOR) || defined(CONFIG_RTOS_HAL_ENABLE_UART_RX_SWITCH)
struct uart_port *serial8250_get_console_port(void)
{
	int port_index = -1;

	if (serial8250_reg.cons)
		port_index = serial8250_reg.cons->index;
#ifdef CONFIG_RTOS_HAL_UART_SUSPEND
	else
		port_index = tty_suspend_index;
#endif

	if ((port_index >= 0) && (port_index < ARRAY_SIZE(serial8250_ports)))
		return &(serial8250_ports[port_index].port);

	return NULL;
}
#endif

#ifdef CONFIG_RTOS_HAL_DOUBLE_CLUSTER
static bool switch_uart;

bool is_switch_uart(void)
{
	return switch_uart;
}

void serial8250_clear_xmit_ring(struct uart_port *port)
{
	struct uart_8250_port *up =
		container_of(port, struct uart_8250_port, port);
	struct circ_buf *xmit = &up->port.state->xmit;
	unsigned int pending_size = 0;

	if (up->port.x_char) {
		up->port.icount.tx++;
		up->port.x_char = 0;
		return;
	}

	pending_size = uart_circ_chars_pending(xmit);
	xmit->tail = (int)(((unsigned int)xmit->tail + pending_size) & (UART_XMIT_SIZE - 1));
	up->port.icount.tx += pending_size;
	uart_write_wakeup(&up->port);
}

static void set_serial8250_clear_xmit_ring(int idx)
{
    unsigned long flags;

	spin_lock_irqsave(&(serial8250_ports[idx].port.lock), flags);
	if (!p_stop_tx)
	    pr_err("p_stop_tx is not setup\n");
	else
	    (*p_stop_tx)(&serial8250_ports[idx]);
	serial8250_clear_xmit_ring(&serial8250_ports[idx].port);
	spin_unlock_irqrestore(&(serial8250_ports[idx].port.lock), flags);
}

void serial8250_start_tx_switch_uart(void)
{
	int i = 0;
	struct uart_port *port = serial8250_get_console_port();

	for (i = 0; i < ARRAY_SIZE(serial8250_ports); i++) {
	    if (serial8250_ports[i].port.type == PORT_UNKNOWN)
		    continue;
		if (&(serial8250_ports[i].port) != port)
		    continue;
		switch_uart = true;
		if (serial8250_ports[i].port.state->port.tty)
		    set_serial8250_clear_xmit_ring(i);
	}
}
EXPORT_SYMBOL(serial8250_start_tx_switch_uart);

void serial8250_start_tx_resume_uart(void)
{
	switch_uart = false;
}
EXPORT_SYMBOL(serial8250_start_tx_resume_uart);
#endif
